package Merlion.FRM.bean;

import Merlion.CRM.bean.MessageManagerBeanRemote;
import Merlion.CRM.entity.ClientEntity;
import Merlion.FRM.entity.CreditProfileEntity;
import javax.ejb.Stateless;
import Merlion.CRM.entity.CustomerEntity;
import Merlion.CRM.entity.SalesOrderEntity;
import Merlion.util.state.CreditProfileState;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
public class CreditProfileBean implements CreditProfileBeanRemote {

    @PersistenceContext
    private EntityManager em;
    @EJB
    private MessageManagerBeanRemote mmb;

    public Long getCreditProfileId(Long customerId) {
        System.out.println("**CreditProfileBean: getCreditProfileId()");

        Query query = em.createQuery("SELECT c.creditProfileId FROM CreditProfileEntity c WHERE c.customerId = :customerId");
        query.setParameter("customerId", customerId);

        Long creditProfileId = (Long) query.getSingleResult();
        System.out.println("**CreditProfileBean: getCreditProfileId() = " + creditProfileId);
        return creditProfileId;
    }

    public Long createCreditProfile(Long customerId, String customerGrade, Double creditLimit, Double creditBalance,
            Double balancePayable, Double paymentAsCIA, List<String> methodOfPayment, String bankName,
            String accNumber, String creditCardType, String creditCardNumber) throws NoResultException {

        System.out.println("**CreditProfileBean: createCreditProfile()");
        CustomerEntity customer = em.find(CustomerEntity.class, customerId);
        Long creditProfileId = null;

        //find if given customer has been registered with a credit profile before
        Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
        query.setParameter("customerId", customerId);

        try {
            if (query.getSingleResult() != null) {
                System.out.println("**CreditProfileBean : Customer has been registered with a credit profile before. Failed to create a new credit profile.");
                return null;
            } else {
                return null;
            }
        } catch (NoResultException ex) {
            if (customer == null) {
                System.out.println("**CreditProfileBean: Customer id is not found. Failed to create a new credit profile.");
                return null;
            } else {
                System.out.println("**CreditProfileBean: createCreditProfile()");
                CreditProfileEntity creditProfile = new CreditProfileEntity();

                creditProfile.setCustomerId(customerId);
                creditProfile.setCreditLimit(1000000.00);
                creditProfile.setCreditBalance(1000000.00);
                creditProfile.setBalancePayable(0.00);
                creditProfile.setCustomerGrade("C");
                creditProfile.setPaymentAsCIA(0.00); //edited if customer got cash-in-advance per sales order
                creditProfile.setCreditProfileStatus("Valid");
                creditProfile.setBankName(bankName);
                creditProfile.setAccountNumber(accNumber);
                creditProfile.setCreditCardType(creditCardType);
                creditProfile.setCreditCardNumber(creditCardNumber);
                creditProfile.setDefaults(0);
                creditProfile.setDeleteFlag("N");

                List<String> method = new ArrayList<String>();
                for (String mop : methodOfPayment) {
                    method.add(mop);
                }

                creditProfile.setMethodOfPayment(method);
                em.persist(creditProfile);
                em.flush();
                creditProfileId = creditProfile.getCreditProfileId();
                System.out.println("**CreditProfileBean: New credit profile has been successfully created.");

                return creditProfileId;
            }
        }
    }

    public void editCreditProfile(Long creditProfileId, Long customerId, String customerGrade, Double creditLimit, Double balancePayable,
            Double creditBalance, Double paymentAsCIA, String creditProfileStatus, int defaults, List<String> methodOfPayment,
            String accountNumber, String bankName, String creditCardType, String creditCardNumber) {

        System.out.println("**CreditProfileManagedBean : editCreditProfile()");
        CreditProfileEntity creditProfile = em.find(CreditProfileEntity.class, creditProfileId);

        if (creditProfile != null && creditProfile.getDeleteFlag().equalsIgnoreCase("N")) {
            System.out.println("**CreditProfileManagedBean: Credit Profile is found.");

            creditProfile.setCreditLimit(creditLimit);
            creditProfile.setCustomerGrade(customerGrade);
            creditProfile.setCreditProfileStatus(creditProfileStatus);//valid or frozen
            creditProfile.setDefaults(defaults);
            creditProfile.setAccountNumber(accountNumber);

            if (creditProfile.getPaymentAsCIA().equals(paymentAsCIA)) {
                creditProfile.setCreditBalance(creditBalance);
                creditProfile.setBalancePayable(balancePayable);
                creditProfile.setPaymentAsCIA(paymentAsCIA);
            } else if (!creditProfile.getPaymentAsCIA().equals(paymentAsCIA)) {
                creditProfile.setCreditBalance(creditProfile.getCreditBalance() - paymentAsCIA);
                creditProfile.setBalancePayable(creditProfile.getBalancePayable() + paymentAsCIA);
                creditProfile.setPaymentAsCIA(creditProfile.getPaymentAsCIA() + paymentAsCIA);
            }

            List<String> method = new ArrayList<String>();
            for (String mop : methodOfPayment) {
                method.add(mop);
            }
            creditProfile.setMethodOfPayment(method);

            creditProfile.setBankName(bankName);
            creditProfile.setCreditCardType(creditCardType);
            creditProfile.setCreditCardNumber(creditCardNumber);
            em.merge(creditProfile);
            em.flush();

            System.out.println("**CreditProfileManagedBean: Credit profile edited");
        } else {
            System.out.println("**CreditProfileManagedBean: Credit profile is not found.");
        }
    }

    //deletion use the creditProfileID, not the customerID
  /*  public void deleteCreditProfile(Long creditProfileId) {
        System.out.println("**CreditProfileBean: deleteCreditProfile()");
        CreditProfileEntity creditProfile = em.find(CreditProfileEntity.class, creditProfileId);

        try {
            if (creditProfile == null) {
                System.out.println("**CreditProfileBean: Credit Profile for the customer is not found.");
            } else if (creditProfile.getDeleteFlag().equalsIgnoreCase("Y")) {
                System.out.println("**CreditProfileBean: Credit Profile has been previously deleted.");
            } else {
                creditProfile.setDeleteFlag("Y");
                em.merge(creditProfile);
                em.flush();
                System.out.println("**CreditProfileBean: Credit profile has been successfully deleted.");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    */
    
    //deletion use the creditProfileID, not the customerID
    public Long deleteCreditProfile(Long creditProfileId) {
        System.out.println("**CreditProfileBean: deleteCreditProfile()");
        CreditProfileEntity creditProfile = em.find(CreditProfileEntity.class, creditProfileId);

            if (creditProfile == null) {
                System.out.println("**CreditProfileBean: Credit Profile for the customer is not found.");
                return null;
            } else if (creditProfile.getDeleteFlag().equalsIgnoreCase("Y")) {
                System.out.println("**CreditProfileBean: Credit Profile has been previously deleted.");
                return null;
            } else {
                creditProfile.setDeleteFlag("Y");
                em.merge(creditProfile);
                em.flush();
                System.out.println("**CreditProfileBean: Credit profile has been successfully deleted.");
                return creditProfileId;
            }
        
    }

    public List<CreditProfileState> viewCreditProfile() {
        System.out.println("**CreditProfileBean : viewCreditProfile()");

        Query q = em.createQuery("SELECT c FROM CreditProfileEntity c");
        List<CreditProfileState> stateList = new ArrayList<CreditProfileState>();

        for (Object o : q.getResultList()) {

            CreditProfileEntity c = (CreditProfileEntity) o;
            if (c.getDeleteFlag().equalsIgnoreCase("N")) {

                CreditProfileState cpState = new CreditProfileState(c.getCreditProfileId(), c.getCustomerId(), c.getCreditLimit(), c.getCreditBalance(),
                        c.getBalancePayable(), c.getPaymentAsCIA(), c.getCustomerGrade(), c.getCreditProfileStatus(),
                        c.getDeleteFlag(), c.getMethodOfPayment(), c.getBankName(), c.getAccountNumber(), c.getCreditCardType(), c.getCreditCardNumber(), c.getDefaults());

                stateList.add(cpState);
            }
        }
        return stateList;
    }

    public List<CreditProfileState> viewDeletedCreditProfile() {
        System.out.println("**CreditProfileBean : viewCreditProfile()");

        Query q = em.createQuery("SELECT c FROM CreditProfileEntity c");
        List<CreditProfileState> stateList = new ArrayList<CreditProfileState>();

        for (Object o : q.getResultList()) {

            CreditProfileEntity c = (CreditProfileEntity) o;
            if (c.getDeleteFlag().equalsIgnoreCase("Y")) {

                CreditProfileState cpState = new CreditProfileState(c.getCreditProfileId(), c.getCustomerId(), c.getCreditLimit(), c.getCreditBalance(),
                        c.getBalancePayable(), c.getPaymentAsCIA(), c.getCustomerGrade(), c.getCreditProfileStatus(),
                        c.getDeleteFlag(), c.getMethodOfPayment(), c.getBankName(), c.getAccountNumber(), c.getCreditCardType(), c.getCreditCardNumber(), c.getDefaults());

                stateList.add(cpState);
            }
        }
        return stateList;
    }

    public boolean overallCreditCheck(Long customerId, Long salesOrderId) {
        System.out.println("**CreditProfileBean: overallCreditCheck()");

        Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
        query.setParameter("customerId", customerId);
        CreditProfileEntity creditProfile = (CreditProfileEntity) query.getSingleResult();

        SalesOrderEntity salesOrder = em.find(SalesOrderEntity.class, salesOrderId);

        if (creditProfile.getDeleteFlag().equalsIgnoreCase("Y") || creditProfile.getCreditProfileStatus().equalsIgnoreCase("frozen")) {
            System.out.println("**CreditProfileBean: Credit check failed.");
            return false;
        } else if (salesOrder.getPaymentMethod().equalsIgnoreCase("Cash")) {
            return true;
        } else if (creditProfile.getCreditLimit() < salesOrder.getTotalPrice()) {
            System.out.println("**CreditProfileBean: Credit check failed.");
            return false;
        } else if (checkPaymentDefault(customerId) == false) {
            System.out.println("**CreditProfileBean: Credit check failed.");
            return false;
        } else if (checkAllowedCredit(customerId) == false) {
            System.out.println("**CreditProfileBean: Credit check failed.");
            return false;
        } else {
            System.out.println("**CreditProfileBean: Credit check is successful.");
            return true;
        }
    }

    //part 1 of credit check
    protected boolean checkPaymentDefault(Long customerId) {
        System.out.println("**CreditProfileBean: checkPaymentDefault()");

        Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
        query.setParameter("customerId", customerId);
        CreditProfileEntity creditProfile = (CreditProfileEntity) query.getSingleResult();

        if (creditProfile.getDefaults() > 0) {
            System.out.println("**CreditProfileBean: Payment default detected for customer: " + customerId);
            return false;
        } else {
            System.out.println("**CreditProfileBean: No payment default detected for customer: " + customerId);
            return true;
        }
    }

    //part 2 of credit check
    @Override
    public boolean checkAllowedCredit(Long customerId) {
        System.out.println("**CreditProfileBean: checkAllowedCredit()");

        Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
        query.setParameter("customerId", customerId);
        try {
            CreditProfileEntity creditProfile = (CreditProfileEntity) query.getSingleResult();
            
            if (creditProfile.getCreditBalance() <= 0.0) {
                System.out.println("**CreditProfileBean: Not enough credit balance for customer: " + customerId);
                return false;
            } else {
                System.out.println("**CreditProfileBean: Credit balance is still available for customer: " + customerId);
                return true;
            }
        } catch (NoResultException ex) {
            System.out.println("Cannot be checked due to " + ex.getMessage());
            return false;
        }

    }

    public void updateCustomerGrade(Long customerId, String grade) {
        System.out.println("**CreditProfileBean: updateCustomerGrade()");

        try {
            Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
            query.setParameter("customerId", customerId);
            CreditProfileEntity creditProfile = (CreditProfileEntity) query.getSingleResult();

            creditProfile.setCustomerGrade(grade);
            em.merge(creditProfile);
            em.flush();

            System.out.println("**CreditProfileBean: Customer grade has been updated.");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void freezeCreditProfile(Long creditProfileId) {
        System.out.println("**CreditProfileBean: freezeCreditProfile()");
        CreditProfileEntity creditProfile = em.find(CreditProfileEntity.class, creditProfileId);

        try {
            if (creditProfile == null) {
                System.out.println("**CreditProfileBean: Credit profile is not found.");
            } else if (creditProfile.getCreditProfileStatus().equalsIgnoreCase("Frozen")) {
                System.out.println("**CreditProfileBean: Credit profile has been previously frozen.");
            } else {
                creditProfile.setCreditProfileStatus("Frozen");
                em.merge(creditProfile);
                em.flush();
                System.out.println("**CreditProfileBean: Credit profile has been successfully frozen.");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void validateCreditProfile(Long creditProfileId) {
        System.out.println("**CreditProfileBean: validateCreditProfile()");
        CreditProfileEntity creditProfile = em.find(CreditProfileEntity.class, creditProfileId);

        try {
            if (creditProfile == null) {
                System.out.println("**CreditProfileBean: Credit profile is not found.");
            } else if (creditProfile.getDeleteFlag().equalsIgnoreCase("Y")) {
                creditProfile.setCreditProfileStatus("Valid");
                creditProfile.setDeleteFlag("N");
                em.merge(creditProfile);
                em.flush();
                System.out.println("**CreditProfileBean: Credit profile has been successfully validated.");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public Double getCreditBalance(Long customerId) {
        System.out.println("**CreditProfileBean: getCreditBalance()");

        try {
            System.out.println("CUSTOMER ID IN GET CREDIT BALANCE " + customerId);
            Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
            query.setParameter("customerId", customerId);

            CreditProfileEntity cp = (CreditProfileEntity) query.getSingleResult();
            Double creditBalance = cp.getCreditBalance();
            return creditBalance;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public int getDefaults(Long customerId) {
        System.out.println("**CreditProfileBean: getDefaults()");

        try {
            Query query = em.createQuery("SELECT c FROM CreditProfileEntity c WHERE c.customerId = :customerId");
            query.setParameter("customerId", customerId);

            CreditProfileEntity cp = (CreditProfileEntity) query.getSingleResult();
            int defaults = cp.getDefaults();
            return defaults;
        } catch (Exception ex) {
            ex.printStackTrace();
            return 0;
        }
    }

    public String getCustomerName(Long customerId) {
        System.out.println("**CreditProfileBean: getCustomerName()");

        ClientEntity ce = em.find(ClientEntity.class, customerId);
        String customerName = ce.getName();
        return customerName;
    }

    public void sendResultForCreditCheck(Long salesOrderId, Long customerId, boolean status) {
        System.out.println("**CreditProfileBean: sendResultForCreditCheck()");
        System.out.println("**CreditProfileBean: Generate email for Customer Executive");
        String result = "";

        if (status) {
            result = "Approved";
        } else {
            result = "Rejected";
        }

        String title = "Result for Credit Check";
        String body = "\n" + "\n" + "Automated message from FINANCE DEPARTMENT to SALES DEPARTMENT" + "\n" + "\n"
                + "Credit check result for the following sales order: " + "\n"
                + "=========================" + "\n"
                + "Sales Order ID      : " + salesOrderId + "\n"
                + "Client ID           : " + customerId + "\n"
                + "Credit Check Result : " + result + "\n"
                + "=========================" + "\n" + "\n" + "\n"
                + "Finance Department" + "\n"
                + "Merlion Pte Ltd";
        
        System.out.println("Sending message");
        mmb.addMessage("Customer Executive", title, body);
        mmb.addMessage("Customer Executive Manager", title, body);
    }
}
